package com.alogic.cron;


import com.alogic.cron.matcher.Counter;
import com.alogic.cron.matcher.Crontab;
import com.alogic.cron.matcher.Interval;
import com.alogic.cron.matcher.Once;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 工厂类
 *
 * @since 1.6.13.7 [20200720 duanyy] <br>
 */
public class CronMatcherFactory {

    /**
     * a slf4j logger
     */
    protected static Logger LOG = LoggerFactory.getLogger(CronMatcherFactory.class);

    /**
     * 类名映射
     */
    protected static Map<String,Class<? extends CronMatcher>> classMappings
            = new HashMap<String,Class<? extends CronMatcher>>();

    /**
     * 分离匹配器和表达式
     */
    protected static Pattern matcherAndExpr = Pattern.compile("^\\(([\\w]*)\\)(.*)$");

    protected static String DFT_MATCHER = "once";

    /**
     * 注册匹配器
     * @param name 名称
     * @param clazz 实现类
     */
    public static void register(String name,Class<? extends CronMatcher> clazz){
        if (StringUtils.isNotEmpty(name) && clazz != null){
            classMappings.put(name,clazz);
        }
    }

    /**
     * 注销匹配器
     * @param name 匹配器名称
     */
    public static void unregister(String name){
        if (StringUtils.isNotEmpty(name)) {
            classMappings.remove(name);
        }
    }

    public static CronMatcher getMatcher(String pattern){
        String matcherId = DFT_MATCHER;
        String expr = pattern;

        Matcher matcher = matcherAndExpr.matcher(pattern);
        if (matcher.find()){
            matcherId = matcher.group(1);
            expr = matcher.group(2);
        }

        if (StringUtils.isEmpty(matcherId)){
            matcherId = DFT_MATCHER;
        }
        matcherId = matcherId.toLowerCase();

        Class<? extends CronMatcher> clazz = getMatcherClass(matcherId);
        try{
            Constructor<? extends CronMatcher> constructor = clazz.getConstructor(
                    new Class[]{String.class}
            );
            return constructor.newInstance(new Object[]{expr});
        }catch (Exception ex){
            LOG.warn("Can not create matcher instance:" + matcherId);
            return new Once(expr);
        }
    }

    protected static Class<? extends CronMatcher> getMatcherClass(String matcherId){
        Class<? extends CronMatcher> found = classMappings.get(matcherId);
        return found == null?Once.class:found;
    }

    static {
        register("once", Once.class);
        register("crontab", Crontab.class);
        register("cron",Crontab.class);
        register("counter", Counter.class);
        register("interval", Interval.class);
    }
}